package com.sys.guacamole;


import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.*;
import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
import org.apache.guacamole.protocol.GuacamoleConfiguration;

import java.util.Date;

/**
 * Created by Administrator on 2019/12/17/017.
 */
public class Guacamole {
    protected String serviceHostname = "127.0.0.1"; // 主机名称
    protected Integer servicePort = 4822; // 主机端口
    protected boolean isRecording = false; // 录像会话状态


    protected GuacamoleConfiguration guacamoleConfiguration = null;
    protected GuacamoleSocket guacamoleSocket = null;
    protected GuacamoleTunnel guacamoleTunnel = null;


    public Guacamole() {
    }

    /**
     * @param serviceHostname 主机名称
     * @param servicePort     主机端口
     */
    public Guacamole(String serviceHostname, Integer servicePort) {
        if (serviceHostname != null && !serviceHostname.equals("")) {
            this.serviceHostname = serviceHostname;
        }
        if (servicePort != null && servicePort > 0) {
            this.servicePort = servicePort;
        }
    }


    /**
     * 打开录像会话
     *
     * @param recordingPath          /data/guacamole/recording 应在其中创建屏幕录像文件的目录。如果需要创建图形记录，则需要此参数。指定此参数将启用图形屏幕记录。如果省略此参数，则不会创建图形记录。
     *                               <p>
     * @param createRecordingPath    如果设置为“ true”，则该recording-path参数指定的目录（ 如果尚不存在）将自动创建。仅将创建路径中的最终目录-如果路径中较早的其他目录不存在，则自动创建将失败，并且将记录错误。
     *                               此参数是可选的。默认情况下，recording-path不会自动创建由参数指定的目录 ，并且在不存在的目录中创建记录的尝试将记录为错误。
     *                               仅当启用图形记录时，此参数才有效。如果recording-path未指定，则将禁用图形会话记录，并且将忽略此参数。
     *                               <p>
     * @param recordingName          用于创建的任何录音的文件名。 此参数是可选的。如果省略，将使用值“ recording”代替。
     *                               仅当启用图形记录时，此参数才有效。如果recording-path未指定，则将禁用图形会话记录，并且将忽略此参数。
     *                               <p>
     * @param recordingExcludeOutput 如果设置为“ true”，则通常从服务器流向客户端的图形输出和其他数据将从记录中排除，从而产生仅包含用户输入事件的记录。此参数是可选的。如果省略，图形输出将包含在记录中。
     *                               仅当启用图形记录时，此参数才有效。如果recording-path未指定，则将禁用图形会话记录，并且将忽略此参数。
     *                               <p>
     * @param recordingExcludeMouse  如果设置为“ true”，则将从记录中排除用户鼠标事件，从而产生缺少可见鼠标光标的记录。此参数是可选的。如果省略，鼠标事件将包含在记录中。
     *                               仅当启用图形记录时，此参数才有效。如果recording-path未指定，则将禁用图形会话记录，并且将忽略此参数。
     *                               <p>
     * @param recordingIncludeKeys   如果设置为“ true”，则用户按键事件将包含在记录中。随后可以通过guaclog实用程序传递记录，以产生对会话期间按下的键的人类可读解释。此参数是可选的。如果省略，则按键事件将不包括在记录中。
     *                               仅当启用图形记录时，此参数才有效。如果recording-path未指定，则将禁用图形会话记录，并且将忽略此参数。
     *                               <p>
     *                               <p>
     *                               <p>
     * @return 录像会话的状态
     */
    public void openRecording(String recordingPath, boolean createRecordingPath, String recordingName,
                              boolean recordingExcludeOutput, boolean recordingExcludeMouse, boolean recordingIncludeKeys) {
        if (recordingPath == null || recordingPath.equals("")) throw new RuntimeException("recordingPath不能为空");
        this.guacamoleConfiguration.setParameter("recording-path", recordingPath);
        this.guacamoleConfiguration.setParameter("create-recording-path", String.valueOf(createRecordingPath));
        if (recordingName != null && !recordingName.equals("")) {
            this.guacamoleConfiguration.setParameter("recording-name", recordingName + new Date().getTime() + ".guacamole");
        } else {
            this.guacamoleConfiguration.setParameter("recording-name", "recording" + new Date().getTime() + ".guacamole");
        }
        this.guacamoleConfiguration.setParameter("recording-exclude-output", String.valueOf(recordingExcludeOutput));
        this.guacamoleConfiguration.setParameter("recording-exclude-mouse", String.valueOf(recordingExcludeMouse));
        this.guacamoleConfiguration.setParameter("recording-include-keys", String.valueOf(recordingIncludeKeys));


        this.isRecording = true;
    }

    /**
     * 关闭录像会话
     *
     * @return 录像会话状态
     */
    public void closeRecording() {
        this.guacamoleConfiguration.unsetParameter("recording-path");
        this.isRecording = false;
    }

    /**
     * 录像会话状态
     *
     * @return 录像会话状态
     */
    public boolean getIsRecording() {
        return isRecording;
    }


    /**
     * 网络参数
     * <p>
     * RDP连接需要定义目标计算机的主机名或IP地址。RDP端口定义为3389，在大多数情况下将为该值。如果不使用端口3389，则仅需要指定RDP端口。
     * <p>
     * SSH连接需要定义目标计算机的主机名或IP地址。SSH被标准化为使用端口22，在大多数情况下，这将是正确的值。如果不使用标准端口，则只需指定SSH端口。
     * <p>
     * Telnet连接需要定义目标计算机的主机名或IP地址。Telnet被标准化为使用端口23，并且在大多数情况下这将是正确的值。如果不使用标准端口，则只需指定telnet端口。
     *
     * @param protocol RDP端口或者SSH或者Telnet
     * @param hostname 子服务端ip
     * @param port     子服务端端口
     */
    public void setGuacamoleConfiguration(String protocol, String hostname, int port) {
        this.guacamoleConfiguration = new GuacamoleConfiguration();
        this.guacamoleConfiguration.setProtocol(protocol);
        this.guacamoleConfiguration.setParameter("hostname", hostname);
        this.guacamoleConfiguration.setParameter("port", String.valueOf(port));
    }

    public GuacamoleConfiguration getGuacamoleConfiguration() {
        return this.guacamoleConfiguration;
    }

    public GuacamoleTunnel getGuacamoleTunnel() throws GuacamoleException {
        this.guacamoleSocket = new ConfiguredGuacamoleSocket(new InetGuacamoleSocket(this.serviceHostname, this.servicePort), getGuacamoleConfiguration());
        this.guacamoleTunnel = new SimpleGuacamoleTunnel(this.guacamoleSocket);
        this.guacamoleTunnel = new DelegatingGuacamoleTunnel(this.guacamoleTunnel);
        return this.guacamoleTunnel;
    }

    public GuacamoleTunnel getGuacamoleTunnel(String protocol, String hostname, Integer port) throws GuacamoleException {
        Guacamole guacamole = new Guacamole(this.serviceHostname, this.servicePort);
        guacamole.setGuacamoleConfiguration(protocol, hostname, port);
        GuacamoleTunnel guacamoleTunnel = guacamole.getGuacamoleTunnel();
        return guacamoleTunnel;
    }


}
